//
//  hookObjcCore.hpp
//  DemoV2
//
//  Created by 董一龙 on 2022/8/5.
//

#ifndef hookObjcCore_hpp
#define hookObjcCore_hpp

#include <stdio.h>
#include <string>
#include <vector>
#include <unordered_set>
#include <tuple>
#include "define.h"
#include <objc/runtime.h>
#include <stack>
#include "Filter.hpp"
#include <queue>
#include "../util/Singleton.hpp"
#include "../CallGraph/CallTree.hpp"


class HookCore{
public:
    struct Config {
        int max_depth;
        uint64_t min_duration;
        std::string log_filename;
        std::vector<DumpConfig> dump_config;
        bool only_main_thread;
    };
    
    struct ObjcCallRecord {
        SEL sel;
        Class cls;
        bool isInstanceMethod;
        uint64_t timestamp;
    };
    
    struct ObjcCallRecordLogInfo {
        struct ObjcCallRecord callRecord;
        uint64_t tid;
        
        union Value {
            uint64_t timestamp;
            uint64_t duration;
        };
        
        union Value unionValue;
        
        enum class LogEvent : uint32_t {
            method_call,
            method_return,
            method_duration,
        };
        LogEvent logEvent;
        
        bool isSuper;
    };
    
    using MethodTimeCost = std::tuple<uint64_t, std::string>;
    
    enum class LogState : uint32_t {
        unknown = 0,
        match_recursion = 1,    ///< 递归跟踪事件：跟踪命中函数的之后所有的调用栈，但是可能被过滤
        mask_recursion = 2, ///< 递归屏蔽事件：屏蔽命中函数，以及其之后的所有的调用栈
    };
    
    static void startHook();
    static void stopHook();
    static void enableLog();
    static void disableLog();
    static HookCore::Config& config();
    

    static void runBeforeObjcMsgSend(id self, Class cls, SEL _cmd, uintptr_t lr);
    static uintptr_t runAfterObjcMsgSend(BOOL is_objc_msgSendSuper);
    static void reset();
    static uint64_t getTimestamp();
    static void log(HookCore::ObjcCallRecordLogInfo const& callRecordLogInfo);
private:
    
    
    static void formatForBeginEvent(HookCore::ObjcCallRecordLogInfo const& callRecordLogInfo, char *buffer, uint32_t size);
    static void formatForEndEvent(HookCore::ObjcCallRecordLogInfo const& callRecordLogInfo, char *buffer, uint32_t size);
    static void formatForDurationEvent(HookCore::ObjcCallRecordLogInfo const& callRecordLogInfo, char *buffer, uint32_t size);
    static std::string getMethodSignture(Class cls, SEL sel, bool isSuper);
    static void updateLogState(HookCore::LogState logState);
    
    
    static bool s_isEnableLog;
public:
    thread_local static std::stack<uintptr_t> t_lrStack;
    thread_local static std::stack<ObjcCallRecord> t_callRecordStack;
    thread_local static std::stack<HookCore::LogState> t_logStateStack;
    thread_local static HookCore::LogState t_logState;
    thread_local static uint32_t t_logStateDepth;
    static Filter filter;
    thread_local static std::vector<CallTree> t_callTreeList;
    thread_local static uint64_t t_timeOffset;
};

#endif /* hookObjcCore_hpp */
